package main

import (
	"bytes"
	"code.google.com/p/gochess/notation/fen"
	pos "code.google.com/p/gochess/position"
	"code.google.com/p/gochess/search"

	"flag"
	"fmt"
	humanize "github.com/dustin/go-humanize"
	"io/ioutil"
	"log"
	"os"
	"runtime/pprof"
	"strconv"
)

func showUsage() {
	fmt.Fprintf(os.Stderr, "usage: ./run_perft_suite -f filename (-r | -i) [-h] [-cpuprofile filename]\n")
	flag.PrintDefaults()
}

// file format:
// <fen string>	<depth>	<perft count>
func main() {

	cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file")
	perftFile := flag.String("f", "", "file with perft positions")
	usage := flag.Bool("h", false, "show help")

	flag.Usage = showUsage
	flag.Parse()
	if *usage {
		showUsage()
		os.Exit(2)
	}

	if *perftFile == "" {
		showUsage()
		os.Exit(2)
	}
	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Printf("could not create file %s\n", *cpuprofile)
			os.Exit(1)
		}
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}
	content, err := ioutil.ReadFile(*perftFile)
	if err != nil {
		pprof.StopCPUProfile()
		log.Fatal(err)
	}
	for i, line := range bytes.Split(content, []byte("\n")) {
		fields := bytes.Fields(bytes.TrimSpace(line))
		no := i + 1
		if len(fields) == 0 || fields[0][0] == '#' {
			// skip empty lines and comments
			continue
		}
		if len(fields) != 8 {
			log.Printf("invalid field count %d in line %d; expected 8\n", len(fields), no)
			log.Printf("skipping line %d\n", no)
			continue
		}
		positionFen := string(bytes.Join(fields[:6], []byte(" ")))
		position, err := fen.Parse(positionFen)
		if err != nil {
			log.Printf("invalid fen notation in line %d: %s", no, err.Error())
			log.Printf("skipping line %d\n", no)
			continue
		}
		depth, err := strconv.Atoi(string(fields[6]))
		if err != nil {
			log.Printf("invalid depth identifier in line %d: %s", no, err.Error())
			log.Printf("skipping line %d\n", no)
			continue
		}
		expected, err := strconv.ParseInt(string(fields[7]), 10, 64)
		if err != nil {
			log.Printf("invalid perft count identifier in line %d: %s", no, err.Error())
			log.Printf("skipping line %d\n", no)
			continue
		}
		found := search.Perft(position, pos.NoMove, int32(depth))
		if found != expected {
			log.Printf("wrong perft count in line %d\n", no)
			log.Printf("fen: '%s'; depth: %d; nodes found: %s; nodes expected: %s\n",
				positionFen, depth, humanize.Comma(found), humanize.Comma(expected))
			continue
		}
		log.Printf("line %d: success\n", no)
	}
}
